package cn.iocoder.yudao.module.system.wechat_card;

import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import cn.iocoder.yudao.module.system.util.HttpUtils;
import cn.iocoder.yudao.module.system.wechat_card.dto.create_card.CardDTO;
import cn.iocoder.yudao.module.system.wechat_card.dto.general_card.GeneralCardUseDTO;
import cn.iocoder.yudao.module.system.wechat_card.dto.giftcard.GiftCardPageDTO;
import cn.iocoder.yudao.module.system.wechat_card.dto.giftcard.UpdateGiftCardPageDTO;
import cn.iocoder.yudao.module.system.wechat_card.dto.order.BatchGetOrderDTO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信礼品卡 对接
 */
@Component
public class WeChatCardUtil {

    @Value("${wx.mp.app-id}")
    private String wechat_app_id;
    @Value("${wx.mp.secret}")
    private String wechat_secret;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SocialClientService socialClientService;

    private static String TOKEN_KEY = "stable_token";

    private static String TOKEN_KEY_WECHAT = "stable_token_wechat";

    //获取stable_token
    private static final String stable_token = "https://api.weixin.qq.com/cgi-bin/stable_token";
    //上传卡券图片素材uploadimg
    private static final String uploadimg = "https://api.weixin.qq.com/cgi-bin/media/uploadimg";
    //创建礼品卡接口
    private static final String create_card = "https://api.weixin.qq.com/card/create";
    //创建-礼品卡货架接口
    private static final String add_giftcard = "https://api.weixin.qq.com/card/giftcard/page/add";
    //查询-礼品卡货架信息接口
    private static final String get_giftcard = "https://api.weixin.qq.com/card/giftcard/page/get";
    //修改-礼品卡货架信息接口
    private static final String update_giftcard = "https://api.weixin.qq.com/card/giftcard/page/update";
    //查询-礼品卡货架列表接口
    private static final String batchget_giftcard = "https://api.weixin.qq.com/card/giftcard/page/batchget";
    //下架-礼品卡货架接口
    private static final String maintain_giftcard = "https://api.weixin.qq.com/card/giftcard/maintain/set";

    //礼品卡订单
    //查询-单个礼品卡订单信息
    private static final String get_order = "https://api.weixin.qq.com/card/giftcard/order/get";
    //查询-批量查询礼品卡订单信息接口
    private static final String batchget_order = "https://api.weixin.qq.com/card/giftcard/order/batchget";

    //礼品卡相关事件-回调

    //使用礼品卡
    //更新用户礼品卡信息接口 当礼品卡被使用后，开发者可以通过该接口变更某个礼品卡的余额信息。
    private static final String generalcard_updateuser = "https://api.weixin.qq.com/card/generalcard/updateuser";
    //核销用户礼品卡接口 当礼品卡被使用完毕或者发生转存、绑定等操作后，开发者可以通过该接口核销用户的礼品卡，使礼品卡在列表中沉底并不再被使用。
    private static final String consume_card = "https://api.weixin.qq.com/card/code/consume";
    //查询礼品卡信息接口 开发者可以通过该接口查询到code对应的信息，如余额、有效期、订单号等，主要用于防止在交易完成后丢单的情况下，用于核销/余额变动时兜底处理。
    private static final String card_get = "https://api.weixin.qq.com/card/code/get";

    /**
     * 获取 Access token  小程序 accessToken
     *
     * @return
     */
    public String getAccessToken() {
        String accessToken = null;
        boolean hasKey = stringRedisTemplate.hasKey(TOKEN_KEY);
        if (hasKey) {
            accessToken = stringRedisTemplate.opsForValue().get(TOKEN_KEY);
            System.err.println("=====================================accessToken");
            System.err.println(accessToken);
        } else {
            SocialClientDO socialClientDO = socialClientService.queryBySocialType(34);
            if (null != socialClientDO) {
                JSONObject requestBody = new JSONObject();
                requestBody.put("appid", socialClientDO.getClientId());
                requestBody.put("secret", socialClientDO.getClientSecret());
                requestBody.put("grant_type", "client_credential");
                Map<String, String> params = new HashMap<String, String>();
                String res = null;
                try {
                    res = HttpUtils.post(stable_token, params, requestBody.toJSONString());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (StringUtils.isNotBlank(res)) {
                        JSONObject result = JSONObject.parseObject(res);
                        if (result.containsKey("access_token")) {
                            accessToken = result.getString("access_token");
                            Integer expires_in = result.getInteger("expires_in");
                            //两小时过期
                            stringRedisTemplate.opsForValue().set(TOKEN_KEY, accessToken, Duration.ofSeconds(expires_in));
                        } else {
                            Integer errcode = result.getInteger("errcode");
                            String errmsg = result.getString("errmsg");
                            System.err.println("getAccessToken-errcode:" + errcode + ",getAccessToken-errmsg:" + errmsg);
                        }
                    }
                }
            }
        }
        return accessToken;
    }

    /**
     * 微信公众号 accessToken
     *
     * @return String
     */
    public String getAccessTokenWeChat() {
        String accessToken = null;
        boolean hasKey = stringRedisTemplate.hasKey(TOKEN_KEY_WECHAT);
        if (hasKey) {
            accessToken = stringRedisTemplate.opsForValue().get(TOKEN_KEY_WECHAT);
            System.err.println("=====================================accessToken");
            System.err.println(accessToken);
        } else {
            SocialClientDO socialClientDO = socialClientService.queryBySocialType(34);
            if (null != socialClientDO) {
                JSONObject requestBody = new JSONObject();
                requestBody.put("appid", wechat_app_id);
                requestBody.put("secret", wechat_secret);
                requestBody.put("grant_type", "client_credential");
                Map<String, String> params = new HashMap<String, String>();
                String res = null;
                try {
                    res = HttpUtils.post(stable_token, params, requestBody.toJSONString());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (StringUtils.isNotBlank(res)) {
                        JSONObject result = JSONObject.parseObject(res);
                        if (result.containsKey("access_token")) {
                            accessToken = result.getString("access_token");
                            Integer expires_in = result.getInteger("expires_in");
                            //两小时过期
                            stringRedisTemplate.opsForValue().set(TOKEN_KEY_WECHAT, accessToken, Duration.ofSeconds(expires_in));
                        } else {
                            Integer errcode = result.getInteger("errcode");
                            String errmsg = result.getString("errmsg");
                            System.err.println("getAccessToken-errcode:" + errcode + ",getAccessToken-errmsg:" + errmsg);
                        }
                    }
                }
            }
        }
        return accessToken;
    }


    /**
     * 上传卡券图片素材 上传图片接口
     *
     * @param file file
     * @return fileUrl
     */
    public String uploadImg(MultipartFile file) {
        String url = null;
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("access_token", getAccessTokenWeChat());
        params.put("type", "image");
        String res = null;
        try {
            BufferedInputStream bis = new BufferedInputStream(file.getInputStream());
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] body_data = null;
            int c = 0;
            byte[] buffer = new byte[8 * 1024];
            try {
                while ((c = bis.read(buffer)) != -1) {
                    baos.write(buffer, 0, c);
                    baos.flush();
                }
                body_data = baos.toByteArray();
                baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 调用自定义的post数据方法，提交表单数据及上传文件
            res = HttpUtils.sendFileData(uploadimg, params, body_data, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                if (result.containsKey("errcode")) {
                    Integer errcode = result.getInteger("errcode");
                    String errmsg = result.getString("errmsg");
                    System.err.println("uploadImg-errcode:" + errcode + ",uploadImg-errmsg:" + errmsg);
                } else {
                    url = result.getString("url");
                }
            }
        }
        return url;
    }

    /**
     * 创建礼品卡
     *
     * @param cardDTO cardDTO
     * @return 礼品卡 card_id
     */
    public String createCard(CardDTO cardDTO) {
        String requestBody = JSON.toJSONString(cardDTO);
        System.out.println("createCard:" + requestBody);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        String card_id = null;
        try {
            res = HttpUtils.post(create_card + "?access_token=" + getAccessTokenWeChat(), params, requestBody);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode == 0) {
                    card_id = result.getString("card_id");
                } else {
                    String errmsg = result.getString("errmsg");
                    System.err.println("createCard-errcode:" + errcode + ",createCard-errmsg:" + errmsg);
                }
            }
        }
        return card_id;
    }

    /**
     * 创建-礼品卡货架接口
     *
     * @param giftCardPageDTO giftCardPageDTO
     * @return 货架的id，用于查询货架详情以及获得货架访问链接
     */
    public String addGiftCard(GiftCardPageDTO giftCardPageDTO) {
        String requestBody = JSON.toJSONString(giftCardPageDTO);
        System.out.println("addGiftCard:" + requestBody);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        String page_id = null;
        try {
            res = HttpUtils.post(add_giftcard + "?access_token=" + getAccessTokenWeChat(), params, requestBody);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode == 0) {
                    page_id = result.getString("page_id");
                } else {
                    String errmsg = result.getString("errmsg");
                    System.err.println("addGiftCard-errcode:" + errcode + ",addGiftCard-errmsg:" + errmsg);
                }
            }
        }
        return page_id;
    }

    /**
     * 查询-礼品卡货架信息接口
     *
     * @param page_id 上一步获取到货架id
     * @return JSONObject
     */
    public JSONObject getGiftCard(String page_id) {
        Map<String, String> params = new HashMap<String, String>();
        JSONObject requestBody = new JSONObject();
        requestBody.put("page_id", page_id);
        String res = null;
        JSONObject jsonObject = null;
        try {
            res = HttpUtils.post(get_giftcard + "?access_token=" + getAccessTokenWeChat(), params, requestBody.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode == 0) {
                    jsonObject = result.getJSONObject("page");
                } else {
                    String errmsg = result.getString("errmsg");
                    System.err.println("getGiftCard-errcode:" + errcode + ",getGiftCard-errmsg:" + errmsg);
                }
            }
        }
        return jsonObject;
    }

    /**
     * 修改-礼品卡货架信息
     *
     * @param updateGiftCardPageDTO updateGiftCardPageDTO
     * @return ok:正常
     */
    public String updateGiftCard(UpdateGiftCardPageDTO updateGiftCardPageDTO) {
        String requestBody = JSON.toJSONString(updateGiftCardPageDTO);
        System.out.println("updateGiftCard:" + requestBody);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        String errmsg = null;
        try {
            res = HttpUtils.post(update_giftcard + "?access_token=" + getAccessTokenWeChat(), params, requestBody);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                errmsg = result.getString("errmsg");
                if (errcode != 0) {
                    System.err.println("updateGiftCard-errcode:" + errcode + ",updateGiftCard-errmsg:" + errmsg);
                }
            }
        }
        return errmsg;
    }

    /**
     * 查询-礼品卡货架列表
     *
     * @return JSONArray
     */
    public JSONArray batchGetGiftCard() {
        JSONObject requestBody = new JSONObject();
        String res = null;
        Map<String, String> params = new HashMap<String, String>();
        JSONArray page_id_list = null;
        try {
            res = HttpUtils.post(batchget_giftcard + "?access_token=" + getAccessTokenWeChat(), params, requestBody.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode == 0) {
                    page_id_list = result.getJSONArray("page_id_list");
                } else {
                    String errmsg = result.getString("errmsg");
                    System.err.println("batchGetGiftCard-errcode:" + errcode + ",batchGetGiftCard-errmsg:" + errmsg);
                }
            }
        }
        return page_id_list;
    }

    /**
     * 下架-礼品卡货架接口
     *
     * @param page_id 需要下架的page_id
     * @return JSONObject
     */
    public JSONObject maintainGiftCard(String page_id) {
        JSONObject requestBody = new JSONObject();
        if (StringUtils.isNotBlank(page_id)) {
            //将某个货架设置为下架
            requestBody.put("page_id", page_id);
            requestBody.put("maintain", true);
        } else {
            //将该商户下所有的货架设置为下架
            requestBody.put("all", true);
            requestBody.put("maintain", true);
        }
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        JSONObject control_info = null;
        try {
            res = HttpUtils.post(maintain_giftcard + "?access_token=" + getAccessTokenWeChat(), params, requestBody.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode == 0) {
                    control_info = result.getJSONObject("control_info");
                } else {
                    String errmsg = result.getString("errmsg");
                    System.err.println("maintainGiftCard-errcode:" + errcode + ",maintainGiftCard-errmsg:" + errmsg);
                }
            }
        }
        return control_info;
    }

    /**
     * 查询-单个礼品卡订单信息
     *
     * @param order_id order_id
     * @return JSONObject
     */
    public JSONObject getOrder(String order_id) {
        JSONObject requestBody = new JSONObject();
        requestBody.put("order_id", order_id);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        JSONObject order = null;
        try {
            res = HttpUtils.post(get_order + "?access_token=" + getAccessTokenWeChat(), params, requestBody.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode == 0) {
                    order = result.getJSONObject("order");
                } else {
                    String errmsg = result.getString("errmsg");
                    System.err.println("getOrder-errcode:" + errcode + ",getOrder-errmsg:" + errmsg);
                }
            }
        }
        return order;
    }

    /**
     * 查询-批量查询礼品卡订单信息接口
     * <p>
     * 注意事项：
     * 1）返回中的total_count是在当前查询条件下的total_count，类似于分页的实现改变offset/count，直到某次请求的$offset+count \ge total_、count$时表示拉取结束。
     * 2）begin_time和end_time的跨度不能超过31天。
     * 3)count不能超过100。
     * 4)sort_type可以填"ASC" / "DESC"，表示对*订单创建时间进行“升 / 降”排序。
     *
     * @param batchGetOrderDTO batchGetOrderDTO
     * @return JSONObject
     */
    public JSONObject batchGetOrder(BatchGetOrderDTO batchGetOrderDTO) {
        String requestBody = JSON.toJSONString(batchGetOrderDTO);
        System.out.println("batchGetOrderDTO:" + requestBody);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        JSONObject result = null;
        try {
            res = HttpUtils.post(batchget_order + "?access_token=" + getAccessTokenWeChat(), params, requestBody);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode != 0) {
                    String errmsg = result.getString("errmsg");
                    System.err.println("addGiftCard-errcode:" + errcode + ",addGiftCard-errmsg:" + errmsg);
                }
            }
        }
        return result;
    }

    /**
     * 更新用户礼品卡信息接口
     *
     * @param generalCardUseDTO generalCardUseDTO
     * @return JSONObject
     */
    public JSONObject generalCardUpdateUser(GeneralCardUseDTO generalCardUseDTO) {
        String requestBody = JSON.toJSONString(generalCardUseDTO);
        System.out.println("generalCardUpdateUser:" + requestBody);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        JSONObject result = null;
        try {
            res = HttpUtils.post(generalcard_updateuser + "?access_token=" + getAccessTokenWeChat(), params, requestBody);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode != 0) {
                    String errmsg = result.getString("errmsg");
                    System.err.println("generalCardUpdateUser-errcode:" + errcode + ",generalCardUpdateUser-errmsg:" + errmsg);
                }
            }
        }
        return result;
    }


    /**
     * 核销用户礼品卡接口
     *
     * @param code    卡券Code码
     * @param card_id 卡券ID,自定义code卡券必填，否则非必填
     * @return ok
     */
    public String consumeCard(String code, String card_id) {
        JSONObject requestBody = new JSONObject();
        requestBody.put("code", code);
        requestBody.put("card_id", card_id);
        System.out.println("consumeCard:" + requestBody);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        String errmsg = null;
        try {
            res = HttpUtils.post(consume_card + "?access_token=" + getAccessTokenWeChat(), params, requestBody.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                JSONObject result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                errmsg = result.getString("errmsg");
                if (errcode != 0) {
                    System.err.println("consumeCard-errcode:" + errcode + ",consumeCard-errmsg:" + errmsg);
                }
            }
        }
        return errmsg;
    }

    /**
     * 查询礼品卡信息接口
     *
     * @param code    卡券Code码
     * @param card_id 卡券ID,自定义code卡券必填，否则非必填
     * @return JSONObject
     */
    public JSONObject cardGet(String code, String card_id) {
        JSONObject requestBody = new JSONObject();
        requestBody.put("code", code);
        requestBody.put("card_id", card_id);
        System.out.println("cardGet:" + requestBody);
        Map<String, String> params = new HashMap<String, String>();
        String res = null;
        JSONObject result = null;
        try {
            res = HttpUtils.post(card_get + "?access_token=" + getAccessTokenWeChat(), params, requestBody.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (StringUtils.isNotBlank(res)) {
                result = JSONObject.parseObject(res);
                Integer errcode = result.getInteger("errcode");
                if (errcode != 0) {
                    String errmsg = result.getString("errmsg");
                    System.err.println("cardGet-errcode:" + errcode + ",cardGet-errmsg:" + errmsg);
                }
            }
        }
        return result;
    }


}
